#include "stdafx.h"
#include "net/SMTPChannel.hpp"
#include "net/MailMessage.hpp"
#include "net/SMTPClientSession.hpp"
#include "net/StringPartSource.hpp"
#include "filesys/environment.hpp"
#include "filesys/file.hpp"
using JHCPP::filesys::CFile;
using JHCPP::filesys::CEnvironment;
#include "stdlib/datetime.hpp"
#include "stdlib/datetimelocal.hpp"
#include "stdlib/datetimeformat.hpp"
#include "stdlib/datetimeformatter.hpp"
using namespace JHCPP::stdlib;
#include "utils/numberformatter.hpp"
using JHCPP::utils::CNumberFormatter;
#include <sstream>
#include <limits>

NET_NAMESPACE_BEGIN

const std::string CSMTPChannel::PROP_MAILHOST("mailhost");
const std::string CSMTPChannel::PROP_SENDER("sender");
const std::string CSMTPChannel::PROP_RECIPIENT("recipient");
const std::string CSMTPChannel::PROP_LOCAL("local");
const std::string CSMTPChannel::PROP_ATTACHMENT("attachment");
const std::string CSMTPChannel::PROP_TYPE("type");
const std::string CSMTPChannel::PROP_DELETE("delete");
const std::string CSMTPChannel::PROP_THROW("throw");


CSMTPChannel::CSMTPChannel()
	: m_mailHost("localhost"),
	m_local(true),
	m_type("text/plain"),
	m_delete(false),
	m_throw(false)
{
}

CSMTPChannel::CSMTPChannel(const std::string& mailhost, const std::string& sender, const std::string& recipient)
	: m_mailHost(mailhost),
	m_sender(sender),
	m_recipient(recipient),
	m_local(true),
	m_type("text/plain"),
	m_delete(false),
	m_throw(false)
{
}

CSMTPChannel::~CSMTPChannel()
{
	try
	{
		close();
	}
	catch (...)
	{
		jh_unexpected();
	}
}

void CSMTPChannel::open()
{
}

void CSMTPChannel::close()
{
}

void CSMTPChannel::log(const CMessage& msg)
{
	try
	{
		CMailMessage message;
		message.setSender(m_sender);
		message.addRecipient(CMailRecipient(CMailRecipient::PRIMARY_RECIPIENT, m_recipient));
		message.setSubject("Log Message from " + m_sender);
		std::stringstream content;
		content << "Log Message\r\n"
			<< "===========\r\n\r\n"
			<< "Host: " << CEnvironment::nodeName() << "\r\n"
			<< "Logger: " << msg.getSource() << "\r\n";

		if (m_local)
		{
			CDateTime dt(msg.getTime());
			content	<< "Timestamp: " << CDateTimeFormatter::format(CLocalDateTime(dt), CDateTimeFormat::RFC822_FORMAT) << "\r\n";
		}
		else
			content	<< "Timestamp: " << CDateTimeFormatter::format(msg.getTime(), CDateTimeFormat::RFC822_FORMAT) << "\r\n";

		content	<< "Priority: " << CNumberFormatter::format(msg.getPriority()) << "\r\n"
			<< "Process ID: " << CNumberFormatter::format(msg.getPid()) << "\r\n"
			<< "Thread: " << msg.getThread() << " (ID: " << msg.getTid() << ")\r\n"
			<< "Message text: " << msg.getText() << "\r\n\r\n";

		message.addContent(new CStringPartSource(content.str()));

		if (!m_attachment.empty())
		{
			{
				CFileInputStream fis(m_attachment, std::ios::in | std::ios::binary | std::ios::ate);
				if (fis.good())
				{
					typedef std::allocator<std::string::value_type>::size_type SST;

					std::streamoff size = fis.tellg();
					//jh_assert(std::numeric_limits<unsigned int>::max() >= size);
					//jh_assert(std::numeric_limits<SST>::max() >= size);
					char* pMem = new char [static_cast<unsigned int>(size)];
					fis.seekg(std::ios::beg);
					fis.read(pMem, size);
					message.addAttachment(m_attachment,
						new CStringPartSource(std::string(pMem, static_cast<SST>(size)), 
						m_type,
						m_attachment));

					delete [] pMem;
				}
			}
			if (m_delete) CFile(m_attachment).remove();
		}

		CSMTPClientSession session(m_mailHost);
		session.login();
		session.sendMessage(message);
		session.close();
	} 
	catch (CException&) 
	{ 
		if (m_throw) throw; 
	}
}

void CSMTPChannel::setProperty(const std::string& name, const std::string& value)
{
	if (name == PROP_MAILHOST) 
		m_mailHost = value;
	else if (name == PROP_SENDER) 
		m_sender = value;
	else if (name == PROP_RECIPIENT) 
		m_recipient = value;
	else if (name == PROP_LOCAL) 
		m_local = isTrue(value);
	else if (name == PROP_ATTACHMENT) 
		m_attachment = value;
	else if (name == PROP_TYPE) 
		m_type = value;
	else if (name == PROP_DELETE) 
		m_delete = isTrue(value);
	else if (name == PROP_THROW) 
		m_throw = isTrue(value);
	else 
		CChannel::setProperty(name, value);
}

std::string CSMTPChannel::getProperty(const std::string& name) const
{
	if (name == PROP_MAILHOST) 
		return m_mailHost;
	else if (name == PROP_SENDER) 
		return m_sender;
	else if (name == PROP_RECIPIENT) 
		return m_recipient;
	else if (name == PROP_LOCAL) 
		return m_local ? "true" : "false";
	else if (name == PROP_ATTACHMENT) 
		return m_attachment;
	else if (name == PROP_TYPE) 
		return m_type;
	else if (name == PROP_DELETE) 
		return m_delete ? "true" : "false";
	else if (name == PROP_THROW) 
		return m_throw ? "true" : "false";
	else
		return CChannel::getProperty(name);
}

void CSMTPChannel::registerChannel()
{
	//CLoggingFactory::defaultFactory().registerChannelClass("SMTPChannel", 
	//	new TInstantiator<CSMTPChannel, CChannel>);
}

bool CSMTPChannel::isTrue(const std::string& value) const
{
	return ((0 == icompare(value, "true")) ||
		(0 == icompare(value, "t")) ||
		(0 == icompare(value, "yes")) ||
		(0 == icompare(value, "y")));
}

NET_NAMESPACE_END
